﻿using YNTK.Common.Configuration;
using YNTK.Common.Const;
using YNTK.Common.Core.Manager;
using YNTK.Common.Enum;
using YNTK.Common.Extension;
using YNTK.Common.Util;
using YNTK.DataEncryption;
using YNTK.Dependency;
using YNTK.DynamicApiController;
using YNTK.EventBridge;
using YNTK.FriendlyException;
using YNTK.JsonSerialization;
using YNTK.OAuth.Service.Dto;
using YNTK.RemoteRequest.Extensions;
using YNTK.System.Entitys.Dto.Permission.User;
using YNTK.System.Entitys.Dto.System.SysLog;
using YNTK.System.Entitys.Permission;
using YNTK.System.Entitys.System;
using YNTK.System.Interfaces.Permission;
using YNTK.System.Interfaces.System;
using YNTK.UnifyResult;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using UAParser;
using Yitter.IdGenerator;

namespace YNTK.OAuth.Service
{
    /// <summary>
    /// 业务实现：身份认证模块
    /// </summary>
    [ApiDescriptionSettings(Tag = "身份认证模块", Name = "OAuth", Order = 799)]
    [Route("api/[controller]")]
    public class OAuthService : IDynamicApiController, ITransient
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ITkUsersService _tkUsersService;//用户服务
        private readonly ITkRoleService _tkRoleService;//角色服务
        private readonly ISysConfigService _sysConfigService; //系统配置服务
        private readonly IUserManager _userManager; // 用户管理
        private readonly ISysCacheService _sysCacheService;//缓存管理
        private readonly IOrganizeService _organizeService;//组织服务
        private readonly IMechanismService _mechanismService;//机构服务

        private readonly SqlSugarScope _db;
        private readonly ITenant _tenant;

        /// <summary>
        /// 构造函数依赖注入
        /// </summary>
        /// <param name="tkUsersService">用户服务</param>
        /// <param name="tkRoleService">角色服务</param>
        /// <param name="sysConfigService">系统配置服务</param>
        /// <param name="httpContextAccessor"></param>
        /// <param name="userManager">用户管理</param>
        /// <param name="sysCacheService">缓存管理</param>
        /// <param name="organizeService">组织服务</param>
        /// <param name="mechanismService">机构服务</param>
        /// <param name="db"></param>
        public OAuthService(ITkUsersService tkUsersService,
            ITkRoleService tkRoleService,
            ISysConfigService sysConfigService,
            IHttpContextAccessor httpContextAccessor,
            IUserManager userManager,
            ISysCacheService sysCacheService,
            IOrganizeService organizeService,
            IMechanismService mechanismService,
            ISqlSugarClient db)
        {
            _tkUsersService = tkUsersService;
            _tkRoleService = tkRoleService;
            _sysConfigService = sysConfigService;
            _httpContextAccessor = httpContextAccessor;
            _userManager = userManager;
            _sysCacheService = sysCacheService;
            _organizeService = organizeService;
            _mechanismService = mechanismService;
            _db = (SqlSugarScope)db;
            _tenant = _db;
        }

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="input">登录输入参数</param>
        /// <returns></returns>
        [HttpPost("Login")]
        [AllowAnonymous]
        [Consumes("application/x-www-form-urlencoded")]
        public async Task<LoginOutput> Login([FromForm] LoginInput input)
        {
            try
            {
                string tenantDbName = App.Configuration["ConnectionStrings:DBName"];
                string tenantId = App.Configuration["ConnectionStrings:ConfigId"];
                string tenantAccout = string.Empty;

                //验证验证码
                string validateCode = await _sysCacheService.GetCode(input.timestamp);
                if (string.IsNullOrWhiteSpace(validateCode)) throw YNTKException.Oh(ErrorCode.D1024);
                if (validateCode != input.code) throw YNTKException.Oh(ErrorCode.D1025);

                if (KeyVariable.MultiTenancy)
                {
                    //分割账号
                    var tenantAccount = input.account.Split('@');
                    tenantId = tenantAccount.FirstOrDefault();
                    if (tenantAccount.Length == 1)
                        input.account = "admin";
                    else
                        input.account = tenantAccount[1];
                    tenantAccout = input.account;

                    var interFace = App.Configuration["YunNanTongKe_App:MultiTenancyDBInterFace"] + tenantId;
                    var response = await interFace.GetAsStringAsync();
                    var data = JSON.Deserialize<RESTfulResult<TenantInterFaceOutput>>(response);
                    if (data.data != null)
                        tenantDbName = data.data.dotnet;
                    else
                        throw YNTKException.Oh(ErrorCode.D1023);

                    _tenant.AddConnection(new ConnectionConfig()
                    {
                        DbType = (DbType)Enum.Parse(typeof(DbType), App.Configuration["ConnectionStrings:DBType"]),
                        ConfigId = tenantId,//设置库的唯一标识
                        IsAutoCloseConnection = true,
                        ConnectionString = string.Format($"{App.Configuration["ConnectionStrings:DefaultConnection"]}", tenantDbName)
                    });
                    _tenant.ChangeDatabase(tenantId);
                }
                //根据用户账号获取用户秘钥
                var user = await _tkUsersService.GetUserInfoByAccount(input.account);
                _ = user ?? throw YNTKException.Oh(ErrorCode.D5002);

                //获取加密后的密码
                var encryptPasswod = MD5Encryption.Encrypt(input.password + user.Secretkey);

                var userAnyPwd = await _tkUsersService.GetUserInfoByLoginAsync(input.account, encryptPasswod);
                _ = userAnyPwd ?? throw YNTKException.Oh(ErrorCode.D1000);
                if(string.IsNullOrWhiteSpace(userAnyPwd.RoleId)) throw YNTKException.Oh(ErrorCode.D1030);

                string organizeId = userAnyPwd?.OrganizeId;//当前登录用户所属组织id
                //企业或者第三方可以通过企业登录页登录
                if(userAnyPwd.AccountType!=0 && userAnyPwd.AccountType != 1 && 
                    (string.IsNullOrWhiteSpace(input.organizeId) || input.organizeId== "org00000000"))
                    throw YNTKException.Oh(ErrorCode.D1026);
                if((userAnyPwd.AccountType== 0 || userAnyPwd.AccountType == 1) &&
                    !string.IsNullOrWhiteSpace(input.organizeId) && input.organizeId != "org00000000")
                    throw YNTKException.Oh(ErrorCode.D1027);
                if (userAnyPwd.AccountType != 0 && userAnyPwd.AccountType != 1 &&
                    !string.IsNullOrWhiteSpace(input.organizeId))
                    organizeId = input.organizeId;

                if (!string.IsNullOrWhiteSpace(organizeId) && organizeId!= "org00000000")
                {
                    var organize = (await _organizeService.GetOrganizeListByIds(new List<string>() { organizeId }))?[0];
                    if (organize == null) throw YNTKException.Oh(ErrorCode.D2002);
                    if (organize.State == OrganizeStateEnum.DidOpen.GetHashCode())
                        throw YNTKException.Oh(ErrorCode.D2039);
                    if (organize.State == OrganizeStateEnum.ServiceMaturity.GetHashCode())
                        throw YNTKException.Oh(ErrorCode.D2040);
                    if (organize.State == OrganizeStateEnum.ServiceTermination.GetHashCode())
                        throw YNTKException.Oh(ErrorCode.D2041);
                    if(userAnyPwd.AccountType != 4 && userAnyPwd.AccountType != 5 && 
                        !string.IsNullOrWhiteSpace(userAnyPwd.OrganizeId) && organizeId!= userAnyPwd.OrganizeId)
                        throw YNTKException.Oh($"您不是组织“{organize.FullName}”的用户！");
                }
                string lastMechanismId = "";
                if (!string.IsNullOrWhiteSpace(userAnyPwd.MechanismId) && userAnyPwd.MechanismId != "jg000000")
                {
                    lastMechanismId = userAnyPwd.MechanismId.Split(',').Last();
                    var mechanism = (await _mechanismService.GetMechanismListAsync(organizeId,new List<string>(){lastMechanismId}))?[0];
                    if(mechanism==null) throw YNTKException.Oh(ErrorCode.D1028);
                    if(mechanism.EnabledMark==0) throw YNTKException.Oh(ErrorCode.D1029);
                }

                // 验证账号是否未被激活
                if (user.EnabledMark == null)
                    throw YNTKException.Oh(ErrorCode.D1018);
                // 验证账号是否被禁用
                if (user.EnabledMark == 0)
                    throw YNTKException.Oh(ErrorCode.D1019);
                // 验证账号是否被删除
                if (user.DeleteMark == 1)
                    throw YNTKException.Oh(ErrorCode.D1017);
                // app权限验证
                if (NetUtil.isMobileBrowser && user.AccountType == 0 && !ExistRoleByApp(user.RoleId))
                    throw YNTKException.Oh(ErrorCode.D1022);

                //登录成功时 判断单点登录信息
                //判断当前用户是否已在其它客户端登录
                bool exist = await _sysCacheService.ExistsUserAsync(tenantId + "_" + user.Id);
                if (exist) await ForceOut(tenantId,tenantDbName,user.Id);

                //token过期时间
                var tokenTimeout = await _sysConfigService.GetInfo("SysConfig", "tokenTimeout");

                var accessToken = string.Empty;
                // 生成Token令牌
                if (KeyVariable.MultiTenancy)
                {
                    accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
                {
                    { ClaimConst.CLAINM_USERID, userAnyPwd.Id },//用户Id
                    { ClaimConst.CLAINM_ACCOUNT, userAnyPwd.Account },//账号
                    { ClaimConst.CLAINM_REALNAME, userAnyPwd.RealName },//用户姓名
                    //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                    { ClaimConst.CLAINM_ADMINISTRATOR, userAnyPwd.AccountType },
                    { ClaimConst.TENANT_ID, tenantId },//租户ID
                    { ClaimConst.TENANT_DB_NAME, tenantDbName },//租户名称
                    { ClaimConst.ORGANIZEID, organizeId??"org00000000" },//所属组织id/企业id
                    { ClaimConst.MECHANISMID, userAnyPwd.MechanismId??"jg000000" },//所属机构id
                    { ClaimConst.LASTMECHANISMID,lastMechanismId},
                    { ClaimConst.ACCOUNTTYPE, userAnyPwd.AccountType },
                    { ClaimConst.ROLEID, userAnyPwd.RoleId }//所属角色id
                }, long.Parse(tokenTimeout.Value));
                }
                else
                {
                    accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
                {
                    { ClaimConst.CLAINM_USERID, userAnyPwd.Id },
                    { ClaimConst.CLAINM_ACCOUNT, userAnyPwd.Account },
                    { ClaimConst.CLAINM_REALNAME, userAnyPwd.RealName },
                    { ClaimConst.CLAINM_ADMINISTRATOR, userAnyPwd.AccountType },
                    { ClaimConst.TENANT_ID, tenantId },
                    { ClaimConst.TENANT_DB_NAME, tenantDbName },
                    { ClaimConst.ORGANIZEID, organizeId??"org00000000" },//所属组织id/企业id
                    { ClaimConst.MECHANISMID, userAnyPwd.MechanismId??"jg000000" },//所属机构id
                    { ClaimConst.LASTMECHANISMID,lastMechanismId},
                    { ClaimConst.ACCOUNTTYPE, userAnyPwd.AccountType },
                    { ClaimConst.ROLEID, userAnyPwd.RoleId }//所属角色id
                }, long.Parse(tokenTimeout.Value));
                }
                var httpContext = _httpContextAccessor.HttpContext;

                // 设置Swagger自动登录
                httpContext.SigninToSwagger(accessToken);

                // 生成刷新Token令牌
                var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, 30);

                // 设置刷新Token令牌
                httpContext.Response.Headers["x-access-token"] = refreshToken;

                var ip = httpContext.GetRemoteIpAddressToIPv4();

                // 修改用户登录信息
                await Event.EmitAsync("User:UpdateUserLoginInfo", new UserEventDealWithInput
                {
                    tenantId = tenantId,
                    tenantDbName = tenantDbName,
                    entity = new UserEntity()
                    {
                        Id = user.Id,
                        FirstLogIP = user.FirstLogIP ?? ip,
                        FirstLogTime = user.FirstLogTime ?? DateTime.Now,
                        PrevLogTime = user.LastLogTime,
                        PrevLogIP = user.LastLogIP,
                        LastLogTime = DateTime.Now,
                        LastLogIP = ip,
                        LogSuccessCount = user.LogSuccessCount + 1
                    }
                });

                //登录时间
                var clent = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);

                // 增加登录日志
                await Event.EmitAsync("Log:CreateVisLog", new LogEventBridgeCrInput
                {
                    tenantId = tenantId,
                    tenantDbName = tenantDbName,
                    entity = new SysLogEntity
                    {
                        Id = YitIdHelper.NextId().ToString(),
                        UserId = user.Id,
                        UserName = user.RealName,
                        OrganizeId= organizeId ?? "org00000000",
                        MechanismId= userAnyPwd.MechanismId ?? "jg000000",
                        Category = 1,
                        IPAddress = ip,
                        Abstracts = "登录成功",
                        PlatForm = clent.String,
                        CreatorTime = DateTime.Now
                    }
                });

                return new LoginOutput()
                {
                    theme = user.Theme == null ? "classic" : user.Theme,//主题
                    language =user.Language,//系统语言
                    backgroundColor =user.BackgroundColor,//导航背景色
                    navigationTextColor =user.NavigationTextColor,//导航文本色
                    token = "Bearer " + accessToken,//token
                    organizeId = organizeId ?? "org00000000",
                    mechanismId = user.ManagerId ?? "jg000000",
                    lastMechanismId= lastMechanismId,
                    roleId = user.RoleId,
                    accountType = (int)user.AccountType,//用户类型
                    accountTypeText = Shipeng.Util.EnumHelper.GetEnumDescriptionString((int)user.AccountType, typeof(AccountType))
                };
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"网络打盹，登录失败！");
            }
        }

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="input">登录输入参数</param>
        /// <returns></returns>
        [HttpPost("LoginApp")]
        [AllowAnonymous]
        [Consumes("application/json")]
        public async Task<LoginOutput> LoginApp(LoginInput input)
        {
            string tenantDbName = App.Configuration["ConnectionStrings:DBName"];
            string tenantId = App.Configuration["ConnectionStrings:ConfigId"];
            string tenantAccout = string.Empty;

            if (KeyVariable.MultiTenancy)
            {
                //分割账号
                var tenantAccount = input.account.Split('@');
                tenantId = tenantAccount.FirstOrDefault();
                if (tenantAccount.Length == 1)
                    input.account = "admin";
                else
                    input.account = tenantAccount[1];
                tenantAccout = input.account;

                var interFace = App.Configuration["YunNanTongKe_App:MultiTenancyDBInterFace"] + tenantId;
                var response = await interFace.GetAsStringAsync();
                var data = JSON.Deserialize<RESTfulResult<TenantInterFaceOutput>>(response);
                if (data.data != null)
                    tenantDbName = data.data.dotnet;
                else
                    throw YNTKException.Oh(ErrorCode.D1023);

                _tenant.AddConnection(new ConnectionConfig()
                {
                    DbType = (DbType)Enum.Parse(typeof(DbType), App.Configuration["ConnectionStrings:DBType"]),
                    ConfigId = tenantId,//设置库的唯一标识
                    IsAutoCloseConnection = true,
                    ConnectionString = string.Format($"{App.Configuration["ConnectionStrings:DefaultConnection"]}", tenantDbName)
                });
                _tenant.ChangeDatabase(tenantId);
            }
            //根据用户账号获取用户秘钥
            var user = await _tkUsersService.GetUserInfoByAccount(input.account);
            _ = user ?? throw YNTKException.Oh(ErrorCode.D5002);

            //获取加密后的密码
            var encryptPasswod = MD5Encryption.Encrypt(input.password + user.Secretkey);

            var userAnyPwd = await _tkUsersService.GetUserInfoByLoginAsync(input.account, encryptPasswod);
            _ = userAnyPwd ?? throw YNTKException.Oh(ErrorCode.D1000);

            // 验证账号是否未被激活
            if (user.EnabledMark == null)
                throw YNTKException.Oh(ErrorCode.D1018);
            // 验证账号是否被禁用
            if (user.EnabledMark == 0)
                throw YNTKException.Oh(ErrorCode.D1019);
            // 验证账号是否被删除
            if (user.DeleteMark == 1)
                throw YNTKException.Oh(ErrorCode.D1017);
            // app权限验证
            if (NetUtil.isMobileBrowser && user.AccountType == 0 && !ExistRoleByApp(user.RoleId))
                throw YNTKException.Oh(ErrorCode.D1022);

            //登录成功时 判断单点登录信息


            //token过期时间
            var tokenTimeout = await _sysConfigService.GetInfo("SysConfig", "tokenTimeout");

            var accessToken = string.Empty;
            // 生成Token令牌
            if (KeyVariable.MultiTenancy)
            {
                accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
                {
                    { ClaimConst.CLAINM_USERID, userAnyPwd.Id },
                    { ClaimConst.CLAINM_ACCOUNT, userAnyPwd.Account },
                    { ClaimConst.CLAINM_REALNAME, userAnyPwd.RealName },
                    { ClaimConst.CLAINM_ADMINISTRATOR, userAnyPwd.AccountType },
                    { ClaimConst.TENANT_ID, tenantId },
                    { ClaimConst.TENANT_DB_NAME, tenantDbName }
                }, long.Parse(tokenTimeout.Value));
            }
            else
            {
                accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
                {
                    { ClaimConst.CLAINM_USERID, userAnyPwd.Id },
                    { ClaimConst.CLAINM_ACCOUNT, userAnyPwd.Account },
                    { ClaimConst.CLAINM_REALNAME, userAnyPwd.RealName },
                    { ClaimConst.CLAINM_ADMINISTRATOR, userAnyPwd.AccountType },
                    { ClaimConst.TENANT_ID, tenantId },
                    { ClaimConst.TENANT_DB_NAME, tenantDbName }
                }, long.Parse(tokenTimeout.Value));
            }
            var httpContext = _httpContextAccessor.HttpContext;

            // 设置Swagger自动登录
            httpContext.SigninToSwagger(accessToken);

            // 生成刷新Token令牌
            var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, 30);

            // 设置刷新Token令牌
            httpContext.Response.Headers["x-access-token"] = refreshToken;

            var ip = httpContext.GetRemoteIpAddressToIPv4();

            // 修改用户登录信息
            await Event.EmitAsync("User:UpdateUserLoginInfo", new UserEventDealWithInput
            {
                tenantId = tenantId,
                tenantDbName = tenantDbName,
                entity = new UserEntity()
                {
                    Id = user.Id,
                    FirstLogIP = user.FirstLogIP ?? ip,
                    FirstLogTime = user.FirstLogTime ?? DateTime.Now,
                    PrevLogTime = user.LastLogTime,
                    PrevLogIP = user.LastLogIP,
                    LastLogTime = DateTime.Now,
                    LastLogIP = ip,
                    LogSuccessCount = user.LogSuccessCount + 1
                }
            });

            //登录时间
            var clent = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);

            // 增加登录日志
            await Event.EmitAsync("Log:CreateVisLog", new LogEventBridgeCrInput
            {
                tenantId = tenantId,
                tenantDbName = tenantDbName,
                entity = new SysLogEntity
                {
                    Id = YitIdHelper.NextId().ToString(),
                    UserId = user.Id,
                    UserName = user.RealName,
                    OrganizeId=user.OrganizeId,
                    MechanismId=user.MechanismId,
                    Category = 1,
                    IPAddress = ip,
                    Abstracts = "登录成功",
                    PlatForm = clent.String,
                    CreatorTime = DateTime.Now
                }
            });

            return new LoginOutput()
            {
                theme = user.Theme == null ? "classic" : user.Theme,
                token = "Bearer " + accessToken
            };
        }




        /// <summary>
        /// 锁屏解锁登录
        /// </summary>
        /// <param name="input">登录输入参数</param>
        /// <returns></returns>
        [HttpPost("LockScreen")]
        public async Task LockScreen([Required] LoginInput input)
        {
            //根据用户账号获取用户秘钥
            var secretkey = (await _tkUsersService.GetUserInfoByAccount(input.account)).Secretkey;

            //获取加密后的密码
            var encryptPasswod = MD5Encryption.Encrypt(input.password + secretkey);

            var user = _tkUsersService.GetUserInfoByLoginAsync(input.account, encryptPasswod);
            _ = user ?? throw YNTKException.Oh(ErrorCode.D1000);
        }

        /// <summary>
        /// 获取当前登录用户信息
        /// </summary>
        /// <returns></returns>
        [HttpGet("loginuser")]
        public async Task<LonginUserDto> GetCurrentUser()
        {
            var httpContext = _httpContextAccessor.HttpContext;
            var user = _userManager.User;
            var loginOutput = new LonginUserDto();
            loginOutput.userInfo = (await _tkUsersService.Get(user.Id)).data;
            (string,string) tuple= await _organizeService.GetLogPath(user.OrganizeId??"");
            loginOutput.userInfo.logId = tuple.Item1;
            loginOutput.userInfo.authorizationCode = tuple.Item2;
           if (!string.IsNullOrWhiteSpace(loginOutput.userInfo.roleId))
            {
                //获取菜单树结构数据
                loginOutput.menuData = await _tkRoleService.GetMenuTreeByRoleId(loginOutput.userInfo.roleId);
                //if (loginOutput.menuData.Any())
                //    loginOutput.menuData = loginOutput.menuData.OrderBy(r => r.sortCode).ToList();
                if(!loginOutput.menuData.Any()) throw YNTKException.Oh(ErrorCode.D1030);
            }
            else throw YNTKException.Oh(ErrorCode.D1030);

            //缓存登录用户菜单权限
            var tokenTimeout = await _sysConfigService.GetInfo("SysConfig", "tokenTimeout");
            loginOutput.userInfo.userId = loginOutput.userInfo.id;
            loginOutput.userInfo.isAdministrator = loginOutput.userInfo.accountType == 1;
            if (!string.IsNullOrWhiteSpace(loginOutput.userInfo.roleId)) 
                loginOutput.userInfo.roleIds = new string[] { loginOutput.userInfo.roleId };
            loginOutput.userInfo.iPAddress = httpContext.GetRemoteIpAddressToIPv4();
            var clent = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);
            loginOutput.userInfo.platForm = clent.String;
            //缓存用户登录信息
            var timeSpan = TimeSpan.FromMinutes(long.Parse(tokenTimeout?.Value??"1440"));
            await _sysCacheService.SetUserInfo(_userManager.TenantId + "_" + user.Id, 
                loginOutput.userInfo, timeSpan);
            await _sysCacheService.SetAsync($"{_userManager.TenantId}_{user.Id}_menucCache",
                loginOutput.menuData, timeSpan);

            return loginOutput;
        }

        /// <summary>
        /// 退出
        /// </summary>
        /// <returns></returns>
        [HttpGet("Logout")]
        public async Task Logout()
        {

            var httpContext = _httpContextAccessor.HttpContext;
            httpContext.SignoutToSwagger();

            var user = _userManager.User;
            await _sysCacheService.DelUserInfo(_userManager.TenantId + "_" + user.Id);
            await _sysCacheService.DelAsync($"{_userManager.TenantId}_{user.Id}_menucCache");
            var clent = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);
            var userContext = App.User;
            var tenantId = userContext?.FindFirstValue(ClaimConst.TENANT_ID);
            var tenantDbName = userContext?.FindFirstValue(ClaimConst.TENANT_DB_NAME);
            //清除IM中的webSocket

            // 增加退出日记
            Event.Emit("Log:CreateVisLog", new LogEventBridgeCrInput
            {
                tenantId = tenantId,
                tenantDbName = tenantDbName,
                entity = new SysLogEntity
                {
                    Id = YitIdHelper.NextId().ToString(),
                    UserId = user.Id,
                    UserName = user.RealName,
                    OrganizeId=user.OrganizeId,
                    MechanismId=user.MechanismId,
                    Category = 1,
                    IPAddress = httpContext.GetRemoteIpAddressToIPv4(),
                    Abstracts = "退出成功",
                    PlatForm = clent.String,
                    CreatorTime = DateTime.Now
                }
            });
        }

        #region PrivateMethod
        /// <summary>
        /// 强制退出
        /// </summary>
        /// <param name="tenantId">租户id</param>
        /// <param name="tenantName">租户数据库名称</param>
        /// <param name="userId">用户id</param>
        /// <returns></returns>
        private async Task ForceOut(string tenantId,string tenantName, string userId)
        {
            var user=await _sysCacheService.GetUserInfo(tenantId + "_" + userId);
            if (user != null)
            {
                await _sysCacheService.DelUserInfo(tenantId + "_" + userId);
                await _sysCacheService.DelAsync($"{tenantId}_{userId}_menucCache");
                //清除IM中的webSocket

                // 增加退出日记
                Event.Emit("Log:CreateVisLog", new LogEventBridgeCrInput
                {
                    tenantId = tenantId,
                    tenantDbName = tenantName,
                    entity = new SysLogEntity
                    {
                        Id = YitIdHelper.NextId().ToString(),
                        UserId = user.id,
                        UserName = user.realName,
                        OrganizeId = user.organizeId,
                        MechanismId = user.mechanismId,
                        Category = 1,
                        IPAddress = user.iPAddress,
                        Abstracts = "其它设备登录强制退出",
                        PlatForm = user.platForm,
                        CreatorTime = DateTime.Now
                    }
                });
            }
        }

        /// <summary>
        /// 判断app用户角色是否存在且有效
        /// </summary>
        /// <param name="roleIds"></param>
        /// <returns></returns>
        private bool ExistRoleByApp(string roleIds)
        {
            if (roleIds.IsEmpty())
            {
                return false;
            }
            var roleIdList1 = roleIds.Split(",").ToList();
            var roleIdList2 = _db.Queryable<RoleEntity>().Where(x => x.DeleteMark == null && x.EnabledMark == 1).Select(x => x.Id).ToList();
            return roleIdList1.Intersect(roleIdList2).ToList().Count > 0;
        }
        #endregion
    }
}
